From cd58dd28c58f6fd37581b0b36ec1f81dcc04008b Mon Sep 17 00:00:00 2001 From: root Date: Sun, 3 May 2015 01:33:53 +0200 Subject: [PATCH] Shell escape process arguments that are printed out cargo build --verbose does output some command lines that cannot be simply copy and pasted into the shell again. The problem is the arguments which are output exactly like this: --feature="foo" When pasted back into the shell, the shell will parse and remove the double quotes. To counteract this, escape special shell characters when printing commandlines. Cargo will print --feature=\"foo\" instead, which can be pasted back into the shell. --- src/cargo/util/mod.rs | 1 + src/cargo/util/process_builder.rs | 3 ++- src/cargo/util/shell_escape.rs | 40 +++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/cargo/util/shell_escape.rs diff --git a/src/cargo/util/mod.rs b/src/cargo/util/mod.rs index e29fa5844..685e5fe47 100644 --- a/src/cargo/util/mod.rs +++ b/src/cargo/util/mod.rs @@ -31,5 +31,6 @@ pub mod toml; pub mod lev_distance; mod dependency_queue; mod sha256; +mod shell_escape; mod vcs; mod mtime; diff --git a/src/cargo/util/process_builder.rs b/src/cargo/util/process_builder.rs index 81d3b92c3..2411424f5 100644 --- a/src/cargo/util/process_builder.rs +++ b/src/cargo/util/process_builder.rs @@ -6,6 +6,7 @@ use std::path::Path; use std::process::{Command, Output}; use util::{CargoResult, ProcessError, process_error}; +use util::shell_escape::shell_escape; #[derive(Clone, PartialEq, Debug)] pub struct ProcessBuilder { @@ -20,7 +21,7 @@ impl fmt::Display for ProcessBuilder { try!(write!(f, "`{}", self.program.to_string_lossy())); for arg in self.args.iter() { - try!(write!(f, " {}", arg.to_string_lossy())); + try!(write!(f, " {}", shell_escape(arg.to_string_lossy()))); } write!(f, "`") diff --git a/src/cargo/util/shell_escape.rs b/src/cargo/util/shell_escape.rs new file mode 100644 index 000000000..d02c1737f --- /dev/null +++ b/src/cargo/util/shell_escape.rs @@ -0,0 +1,40 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::borrow::Cow; + +static SHELL_SPECIAL: &'static str = r#"\$'"`!"#; + +/// Escape characters that may have special meaning in a shell. +pub fn shell_escape(s: Cow) -> Cow { + let escape_char = '\\'; + // check if string needs to be escaped + let clean = SHELL_SPECIAL.chars().all(|sp_char| !s.contains(sp_char)); + if clean { + return s + } + let mut es = String::with_capacity(s.len()); + for ch in s.chars() { + if SHELL_SPECIAL.contains(ch) { + es.push(escape_char); + } + es.push(ch) + } + es.into() +} + +#[test] +fn test_shell_escape() { + assert_eq!(shell_escape("--aaa=bbb ccc".into()), "--aaa=bbb ccc"); + assert_eq!(shell_escape(r#"--features="default""#.into()), + r#"--features=\"default\""#); + assert_eq!(shell_escape(r#"'!\$` \\ \n"#.into()), + r#"\'\!\\\$\` \\\\ \\n"#); +} -- 2.30.2